#!/usr/bin/python
import sys, os, stat, commands
sys.path=[os.path.abspath('..')]+ sys.path

from inspect import isclass, isfunction, isroutine
def scandir(dir, files=[]):
    for file in os.listdir(dir):
        path = os.path.join(dir, file)
        if os.path.isfile(path) and path.endswith(".pyx"):
            files.append(path.replace(os.path.sep, ".")[2:-4])
        elif os.path.isdir(path):
            scandir(path, files)
    return files


def findpackages(dir,files=[], ):
    for file in os.listdir(dir):
        if file!="build":
            path = os.path.join(dir, file)
            if os.path.isdir(path):# and path.endswith(".py"):
                for file1 in os.listdir(path):
                    if file1=="__init__.py":
                        files.append(path.replace(os.path.sep, ".")[3:])
                findpackages(path, files)
    return files

#def get_classes(fname):

def write_file_header(f,i):
    title=":mod:`"+i+"`\n"
    f.write(".. Autogenerated file. Do not modify\n\n")
    f.write(title)
    f.write("="*(len(title)-1)+"\n\n")
    f.write(".. automodule:: "+i+"\n")
    
def get_class_list(module):
    r=[]
    try:
        oblist=module.__all__
    except(AttributeError):
        return r
    
    for o in oblist:
        obj=module.__dict__[o]
        if isclass(obj):
            r.append(o)
    return r

def get_function_list(module):
    r=[]
    try:
        oblist=module.__all__
    except(AttributeError):
        return r
    
    for o in oblist:
        obj=module.__dict__[o]
        if isfunction(obj) or isroutine(obj):
            r.append(o)
    return r
    

def document_packages(packages):
    for i in packages:
        import_string = "import "+i+" as module"
        print "Documenting "+i
        exec import_string
        
        try:
            oblist=module.__all__
        except(AttributeError):
            print "*****************************************************"
            print "Warning:  Package "+i+" \n"+\
                  "has no __all__ attribute in the __init__.py file\n"+\
                  "This is needed to know what to document. Please\n"+\
                  "add the __all__ attribute if you want this package\ndocumented" 
            print "*****************************************************"
            
            continue
            
        
        #rstname=i.split(".")[-1]+".rst"
        rstname=i.replace(".","_")+".rst"
        #print rstname
        frst=open(rstname,"w")
        
        
        write_file_header(frst,i)
        
        # Class List
       
        clist=get_class_list(module)
        if len(clist)>0: frst.write("\n\n**Class List**\n--------------\n\n")
        for o in clist:
            frst.write("- :class:`"+o+"`\n") 
        frst.write("\n")
        
        #Module Functions LIST
        
        flist=get_function_list(module)
        if len(flist)>0: frst.write("\n\n**Function List**\n-----------------\n\n")
        for o in flist:
            frst.write("- :func:`"+o+"`\n") 
        frst.write("\n")
        
        #Generate Class documentation
        if len(clist)>0:frst.write("\n\n**Available Classes**\n---------------------\n\n")
            
        for o in clist:
            #print " ",o
            obj=module.__dict__[o]
            fname="../"+obj.__module__.replace(".","/")
            try:
                f=open(fname+".pyx","r")
            except(IOError):
                f=open(fname+".py","r")
            code = f.readlines()
            f.close()
            
            
            ide=0
            cl=""
            #Find the begining of the class definition
            for n,line in enumerate(code):
                #find cython class definitions
                if len(line.split())>1 and line.find(o)!=-1 and line.split()[1]=="class" and (line.split()[0]=="def" or line.split()[0]=="cdef"):
                    #cl=line.split()[2][:-1]
                    #cl=cl.split("(")[0]
                    cl=o
                    line1=line.strip()
                    ide = len(line)-len(line1)
                    break
                #find python class definitions
                if len(line.split())>1 and line.find(o)!=-1 and line.split()[0]=="class":
                    #cl=line.split()[2][:-1]
                    #cl=cl.split("(")[0]
                    cl=o
                    line1=line.strip()
                    ide = len(line)-len(line1)
                    break
            
            code=code[n+1:]
            
            methods=[]
            signature="()"
            for line in code:
                #New Class found
                line1=line.strip()
                
                if len(line1.split(" "))>1 and line1.split(" ")[1]=="class"and (line1.split(" ")[0]=="def" or line1.split(" ")[0]=="cdef"):
                    break
               
                #Deidentation found
                
                if (len(line)-len(line1))<=ide and (line1.split(" ")[0]=="def" or line1.split(" ")[0]=="cdef" or line1.split(" ")[0]=="cpdef"):
                    break
              
                
                # Find the init for the class constructor signature
                
                if line1.split(" ")[0]=="def" and line1.find("__init__")!=-1 :#and line.split(" ")[0]=="def":
                
                    c=line1.find("(")
                    if c==-1: signature="()"
                    else: 
                        signature=line1[c:-1]
                        c=signature.find(",")
                        if c==-1 : signature="()"
                        else:signature="("+signature[c+1:]
                    
                #Find other public methods
                if (line1.split(" ")[0]=="def" or line1.split(" ")[0]=="cpdef" ) and line1.find(" _")==-1 :#and line.split(" ")[0]=="def":
                    
                    #Find Argument
                    sp=line.find("(")
                    argument=line1[sp:-1]
                    mdef=line1[:sp]
                    mname=mdef.split()[-1]
                    
                    #print "  ",mname+argument
                    methods.append(mname+argument)
                
                
                    
            if cl!="":
                if o != clist[0]: frst.write("\n.....\n\n")
                frst.write(".. autoclass:: "+cl+signature+"\n")
                frst.write("    \n    \n")
                frst.write("    **AVAILABLE METHODS**\n\n")
                methods.sort()
                for method in methods:
                    frst.write("    .. automethod:: "+method+"\n")
                

        #Generate function documentation
        methods=[]
        for o in flist:
            print " ",o
            obj=module.__dict__[o]
            fname="../"+obj.__module__.replace(".","/")
            try:
                f=open(fname+".pyx","r")
            except(IOError):
                f=open(fname+".py","r")
            code = f.readlines()
            f.close()
            
            
            signature="()"
            for line in code:
                 
                #Find other public functions
                if (line.split(" ")[0]=="def" or line.split(" ")[0]=="cpdef" ) and line.find(" _")==-1 and line.find(" class ")==-1 and (line[0]=="d" or line[0]=="c") and line.find(o)!=-1:
                    line1=line.strip()
                    #Find Argument
                    sp=line1.find("(")
                    argument=line1[sp:-1]
                    mdef=line1[:sp]
                    mname=mdef.split()[-1]
                    
                    #print "  ",mname+argument
                    methods.append(mname+argument)
                
                
                    
        if len(methods)>0:
            
            frst.write("\n\n**Available Functions**\n-----------------------\n\n")
            methods.sort()
            for method in methods:
                if method != methods[0]: frst.write("\n.....\n\n")
                frst.write(".. autofunction:: "+method+"\n")
        
        frst.close()
        

#Autogenerating raytrace packages list

packages=findpackages('../pyoptools/raytrace')
document_packages(packages)

packages1=findpackages('../pyoptools/misc')
document_packages(packages1)

